package com.github.aloxc.plugin.restplus.listener;

import com.github.aloxc.plugin.restplus.common.Consts;
import com.github.aloxc.plugin.restplus.common.RequestHelper;
import com.github.aloxc.plugin.restplus.entity.EnvironmentConfig;
import com.github.aloxc.plugin.restplus.entity.RestConfig;
import com.github.aloxc.plugin.restplus.entity.Setting;
import com.github.aloxc.plugin.restplus.entity.UserCase;
import com.github.aloxc.plugin.restplus.i18n.I18Bundle;
import com.github.aloxc.plugin.restplus.method.HttpMethod;
import com.github.aloxc.plugin.restplus.navigator.RestServiceDetail;
import com.github.aloxc.plugin.restplus.navigator.RestServicesNavigator;
import com.github.aloxc.plugin.restplus.test.RestRequest;
import com.github.aloxc.plugin.restplus.test.RestResponse;
import com.github.aloxc.plugin.restplus.test.TestResult;
import com.github.aloxc.plugin.restplus.utils.JsonUtils;
import com.github.aloxc.plugin.restplus.utils.StringUtils;
import com.github.aloxc.plugin.restplus.utils.ToolkitUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import org.jetbrains.annotations.NotNull;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class TestAllListener implements ActionListener {
    private RestServiceDetail restServiceDetail;
    public TestAllListener(RestServiceDetail restServiceDetail){
        this.restServiceDetail = restServiceDetail;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (StringUtils.isNullOrEmpty(restServiceDetail.getUrl())) {
            return;
        }
        ProgressManager.getInstance().run(new Task.Backgroundable(null, I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.send.tiptext")) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                final Runnable runnable = () -> {
                    restServiceDetail.getSearchMap().clear();
                    restServiceDetail.setSearchIndex(0);
                    RestConfig config = restServiceDetail.getProject().getComponent(RestServicesNavigator.class).getConfig();
                    EnvironmentConfig environmentConfig = null;
                    Map<String, Setting> baseHeaderMap = new HashMap(2 << 3);
                    Map<String, Setting> baseCookieMap = new HashMap(2 << 3);

                    Map<String, Setting> headerMap = new HashMap(2 << 3);
                    Map<String, Setting> cookieMap = new HashMap(2 << 3);

                    StringBuffer baseScript = new StringBuffer();
                    int allCount = 0;
                    int successCount = 0;
                    int failCount = 0;
                    if (config != null && config.getGlobalConfig() != null) {
                        if (!StringUtils.isNullOrEmpty(config.getGlobalConfig().getTest())) {
                            baseScript.append("\n").append(config.getGlobalConfig().getTest());
                        }
                        config.getGlobalConfig().getSettingList().stream().filter(ele -> ele.isSelected()).forEach(it -> {
                            if (Consts.VariateType.HEADER.getType().equals(it.getType())) {
                                baseHeaderMap.put(it.getName(), it);
                            } else if (Consts.VariateType.COOKIE.getType().equals(it.getType())) {
                                baseCookieMap.put(it.getName(), it);
                            }
                        });
                    }

                    if (config != null && config.getEnv() != null && config.getEnv().size() > 0) {
                        Map<String, EnvironmentConfig> envMap = config.getEnv();
                        for (String envName : envMap.keySet()) {
                            if (envMap.get(envName).isSelected()) {
                                environmentConfig = envMap.get(envName);
                                if (!StringUtils.isNullOrEmpty(environmentConfig.getTest())) {
                                    baseScript.append("\n").append(environmentConfig.getTest());
                                }
                                if (environmentConfig.getSettingList() != null) {
                                    environmentConfig.getSettingList().stream().filter(ele -> ele.isSelected()).forEach(it -> {
                                        if (Consts.VariateType.HEADER.getType().equals(it.getType())) {
                                            baseHeaderMap.put(it.getName(), it);
                                        } else if (Consts.VariateType.COOKIE.getType().equals(it.getType())) {
                                            baseCookieMap.put(it.getName(), it);
                                        }
                                    });
                                }
                                break;
                            }
                        }
                    }

                    if (config != null && config.getRequestConfig() != null && config.getRequestConfig().size() > 0 &&
                            config.getRequestConfig().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()) != null) {
                        if (!StringUtils.isNullOrEmpty(config.getRequestConfig().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()).getTest())) {
                            baseScript.append("\n").append(config.getRequestConfig().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()).getTest());
                        }
                        config.getRequestConfig().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()).getSettingList().stream().filter(ele -> ele.isSelected()).forEach(it -> {
                            if (Consts.VariateType.HEADER.getType().equals(it.getType())) {
                                baseHeaderMap.put(it.getName(), it);
                            } else if (Consts.VariateType.COOKIE.getType().equals(it.getType())) {
                                baseCookieMap.put(it.getName(), it);
                            }
                        });
                    }


                    if (config != null && config.getUserCaseMap() != null && config.getUserCaseMap().size() > 0 &&
                            config.getUserCaseMap().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()) != null
                            && config.getUserCaseMap().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl()).size() > 0) {
                        Map<String, UserCase> userCaseMap = config.getUserCaseMap().get((restServiceDetail.getParentName() != null ? restServiceDetail.getParentName() + ":" : "") + restServiceDetail.getUrl());
                        for (String k : userCaseMap.keySet()) {
                            StringBuffer script = new StringBuffer(baseScript);
                            headerMap.putAll(baseHeaderMap);
                            cookieMap.putAll(baseCookieMap);
                            userCaseMap.get(k).getHeaderMap().keySet().stream().forEach(uk -> {
                                Setting s = new Setting();
                                s.setSelected(true);
                                s.setName(uk);
                                s.setType(Consts.VariateType.HEADER.getType());
                                s.setValue(String.valueOf(userCaseMap.get(k).getHeaderMap().get(uk)));
                                headerMap.put(uk, s);
                            });

                            Map<String, Object> paramMap = userCaseMap.get(k).getParamMap();
                            Map<String, Object> paramMap1 = new HashMap<>(2 << 3);
                            paramMap1.putAll(paramMap);
                            Set<String> usedKeySet = new HashSet<>(2 << 3);
                            String tempUrl = restServiceDetail.getUrl();
                            if (paramMap1 != null && paramMap1.size() > 0) {
//                                    paramMap1.putAll(paramMap);
                                String prev = tempUrl;
                                for (String key : paramMap1.keySet()) {
                                    tempUrl = tempUrl.replaceFirst("\\{(" + key + "[\\s\\S]*?)\\}", String.valueOf(paramMap1.get(key)));
                                    if (!prev.equals(tempUrl)) {
                                        usedKeySet.add(key);
                                    }
                                    prev = tempUrl;
                                }
                            }
                            usedKeySet.stream().forEach(usk -> paramMap1.remove(usk));
                            String params = ToolkitUtil.textToRequestParam(paramMap1);
                            if (params.length() != 0) {
                                // 包含了参数
                                if (tempUrl.contains("?")) {
                                    tempUrl += "&" + params;
                                } else {
                                    tempUrl += "?" + params;
                                }
                            }

                            boolean https = environmentConfig.isHttps();
                            String context = environmentConfig.getContext();
                            String tempContext = context;
                            if (!StringUtils.isNullOrEmpty(tempContext)) {
                                if (!tempContext.startsWith("/")) {
                                    tempContext = "/" + tempContext;
                                }
                                if (tempContext.endsWith("/")) {
                                    tempContext = tempContext.substring(0, tempContext.length() - 1);
                                }
                            } else {
                                tempContext = "";
                            }
                            tempUrl = (https ? "https://" : "http://") + environmentConfig.getHost() + ":" + environmentConfig.getPort() + tempContext + tempUrl;
                            RestResponse response;
                            if (!StringUtils.isNullOrEmpty(userCaseMap.get(k).getTest())) {
                                script.append("\n").append(userCaseMap.get(k).getTest());
                            }
                            RestRequest request = new RestRequest();
                            request.setUrl(tempUrl);
                            request.setHeaderList(headerMap.values());
                            request.setCookieList(cookieMap.values());
                            request.setScript(script.toString());
                            if ("POST".equals(restServiceDetail.getMethod().toUpperCase())) {
                                if (restServiceDetail.getRequestBodyTextArea() != null
                                        && !StringUtils.isNullOrEmpty(restServiceDetail.getRequestBodyTextArea().getText())
                                        && !"null".equals(restServiceDetail.getRequestBodyTextArea().getText())) {
                                    request.setBody(JsonUtils.toJson(userCaseMap.get(k).getBodyMap(), false));
                                    request.setHttpMethod(HttpMethod.POST_BODY);
                                } else {
                                    request.setHttpMethod(HttpMethod.getByRequestMethod(restServiceDetail.getMethod()));
                                }
                            } else {
                                request.setHttpMethod(HttpMethod.getByRequestMethod(restServiceDetail.getMethod()));
                            }
                            request.setService(restServiceDetail.getUrl());
                            request.addRequetListener(new RestRequestHistoryListener(restServiceDetail.getParentName()));
                            response = RequestHelper.request(restServiceDetail.getProject(), restServiceDetail.getModule(), restServiceDetail.getUrlTree(), request);
                            restServiceDetail.addContent(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.test.result.requestcase.text") + "[" + k + "]");
                            if (response != null) {
                                restServiceDetail.consoleTest(response);
                                int sc = (int) response.getTestResultList().stream().filter(TestResult::isSuccess).count();
                                allCount += response.getTestResultList().size();
                                successCount += sc;
                                failCount += response.getTestResultList().size() - sc;
                            }
                        }
                    }
                    restServiceDetail.setTestIcon(allCount, successCount, failCount);
                };
                runnable.run();
            }
        });
    }
}
